﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Gmantis.Controls.DataGrid
{
    internal class DataGridGroupManager
    {
        // Fields
        private DataGridColumn[] _groupedColumns;
        private GroupedField[] _groupedFields;

        // Events
        public event EventHandler GroupChanged;

        // Methods
        internal DataGridGroupManager(DataGridModel model)
        {
            this.Model = model;
        }

        public void GroupBy(DataGridColumnValue<DataGridSortDirection>[] columns)
        {
            this.GroupBy(columns, false);
        }

        public void GroupBy(DataGridColumnValue<DataGridSortDirection>[] columns, bool preserveOtherColumnsGrouping)
        {
            DataGridColumnValue<DataGridSortDirection>[] valueArray = columns;
            if (preserveOtherColumnsGrouping)
            {
                List<DataGridColumnValue<DataGridSortDirection>> source = (from column in this.GroupedColumns select new DataGridColumnValue<DataGridSortDirection>(column, column.GroupState.Direction)).ToList<DataGridColumnValue<DataGridSortDirection>>();
                DataGridColumnValue<DataGridSortDirection>[] valueArray2 = columns;
                for (int i = 0; i < valueArray2.Length; i++)
                {
                    Func<DataGridColumnValue<DataGridSortDirection>, bool> predicate = null;
                    DataGridColumnValue<DataGridSortDirection> columngroupInfo = valueArray2[i];
                    if (predicate == null)
                    {
                        predicate = gi => gi.Column == columngroupInfo.Column;
                    }
                    DataGridColumnValue<DataGridSortDirection> value2 = source.FirstOrDefault<DataGridColumnValue<DataGridSortDirection>>(predicate);
                    if (value2 == null)
                    {
                        source.Add(columngroupInfo);
                    }
                    else
                    {
                        value2.Value = columngroupInfo.Value;
                    }
                }
                valueArray = source.ToArray();
            }
            DataGridGroupChangingEventArgs e = new DataGridGroupChangingEventArgs(valueArray);
            this.Model.DataGrid.OnGroupChanging(e);
            if (!e.Cancel)
            {
                if (!this.Model.DataGrid.IsGroupingRowsAllowed)
                {
                    throw new DataGridGroupException("Grouping rows isn't allowed.");
                }
                try
                {
                    this.Model.DataConnection.GroupedFields = (from gi in valueArray select new GroupedField { PropertyName = gi.Column.ActualSortMemberPath, Direction = gi.Value, GroupConverter = gi.Column.GroupConverter }).ToArray<GroupedField>();
                }
                catch (Exception exception)
                {
                    throw new DataGridGroupException("There was an error when grouping rows.", exception);
                }
            }
        }

        public void InsertGroup(DataGridColumn column, int index)
        {
            List<DataGridColumn> list = this.GroupedColumns.ToList<DataGridColumn>();
            if (list.Contains(column))
            {
                list.Remove(column);
            }
            List<DataGridColumnValue<DataGridSortDirection>> list2 = (from c in list select new DataGridColumnValue<DataGridSortDirection>(c, c.GroupState.Direction)).ToList<DataGridColumnValue<DataGridSortDirection>>();
            list2.Insert(index, new DataGridColumnValue<DataGridSortDirection>(column, DataGridSortDirection.Ascending));
            this.GroupBy(list2.ToArray());
        }

        public void InvalidateGroupedColumns()
        {
            this._groupedColumns = null;
        }

        private void OnGroupChanged()
        {
            if (this.GroupChanged != null)
            {
                this.GroupChanged(this, new EventArgs());
            }
        }

        public void RemoveGroup(DataGridColumn column)
        {
            List<DataGridColumn> list = this.GroupedColumns.ToList<DataGridColumn>();
            list.Remove(column);
            this.GroupBy((from c in list select new DataGridColumnValue<DataGridSortDirection>(c, c.GroupState.Direction)).ToArray<DataGridColumnValue<DataGridSortDirection>>());
        }

        public void SetCurrentGroupedColumns(GroupedField[] groupedFields)
        {
            this._groupedFields = groupedFields;
            List<DataGridColumnValue<DataGridSortDirection>> list = new List<DataGridColumnValue<DataGridSortDirection>>();
            List<DataGridColumnValue<DataGridSortDirection>> list2 = new List<DataGridColumnValue<DataGridSortDirection>>();
            foreach (DataGridColumn column in this.GroupedColumns)
            {
                list.Add(new DataGridColumnValue<DataGridSortDirection>(column, column.GroupState.Direction));
            }
            int num = 0;
            bool flag = false;
            GroupedField[] fieldArray = groupedFields;
            for (int i = 0; i < fieldArray.Length; i++)
            {
                Func<DataGridColumn, bool> predicate = null;
                GroupedField field = fieldArray[i];
                if (predicate == null)
                {
                    predicate = c => c.ActualSortMemberPath == field.PropertyName;
                }
                DataGridColumn column2 = this.Model.Columns.FirstOrDefault<DataGridColumn>(predicate);
                DataGridSortDirection direction = field.Direction;
                list2.Add(new DataGridColumnValue<DataGridSortDirection>(column2, direction));
                if (column2 != null)
                {
                    flag |= (column2.GroupState.Index != num) || (column2.GroupState.Direction != direction);
                    column2.GroupState.Set(direction, new int?(num++));
                }
            }
            DataGridColumn[] groupedColumns = this.GroupedColumns;
            for (int j = 0; j < groupedColumns.Length; j++)
            {
                Func<GroupedField, bool> func2 = null;
                DataGridColumn column = groupedColumns[j];
                if (func2 == null)
                {
                    func2 = field => field.PropertyName == column.ActualSortMemberPath;
                }
                if (groupedFields.Where<GroupedField>(func2).Count<GroupedField>() == 0)
                {
                    int? index = null;
                    column.GroupState.Set(DataGridSortDirection.None, index);
                    flag = true;
                }
            }
            if (flag)
            {
                this.InvalidateGroupedColumns();
                DataGridGroupChangedEventArgs e = new DataGridGroupChangedEventArgs(list2.ToArray(), list.ToArray());
                this.OnGroupChanged();
                this.Model.DataGrid.OnGroupChanged(e);
            }
        }

        // Properties
        public int GroupCount
        {
            get
            {
                if (this._groupedFields != null)
                {
                    return this._groupedFields.Length;
                }
                return 0;
            }
        }

        public DataGridColumn[] GroupedColumns
        {
            get
            {
                Func<GroupedField, IEnumerable<DataGridColumn>> selector = null;
                if (this._groupedColumns == null)
                {
                    if (this.GroupedFields != null)
                    {
                        if (selector == null)
                        {
                            selector = gf => from c in this.Model.Columns
                                             where c.ActualSortMemberPath == gf.PropertyName
                                             select c;
                        }
                        this._groupedColumns = this.GroupedFields.SelectMany<GroupedField, DataGridColumn>(selector).Distinct<DataGridColumn>().ToArray<DataGridColumn>();
                    }
                    else
                    {
                        this._groupedColumns = new DataGridColumn[0];
                    }
                }
                return this._groupedColumns;
            }
        }

        public GroupedField[] GroupedFields
        {
            get
            {
                return this._groupedFields;
            }
        }

        private DataGridModel Model { get; set; }
    }
}
